package com.culture.bootdemo.controller;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author: wen
 * @date: 2023/7/5 13:59
 * redisson 分布式锁：
 */
//@RestController
@Slf4j
//@RequestMapping("/redisLock")
public class RedissonLockController {

    /**
     * 使用redis本身的 setNX方法出现的问题：
     * 1.   锁超时问题： 可以设置超时时间
     * 2.   释放锁时候需要先获取，非原子性
     *
     */

    /**
     * 商品在Redis中的key名称
     */
    private static final String KEY_STOCK = "stock";

    @Resource
    RedisTemplate<String, String> redisTemplate;

    @Autowired
    RedissonClient redissonClient;


    /**
     * redisson 分布式锁
     */
    @GetMapping("lock")
    public void test() {
        // 分布式锁名称，随便什么都可以，重要的是两个应用要共享这一个Redis的key
        String lockKey = "lockDeductStock";
        // 获取锁对象
        RLock redissonLock = redissonClient.getLock(lockKey);
        try {
            // -----加锁-----
            // 类似于Redis的一条setnx命令：Boolean lockResult = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 30, TimeUnit.SECONDS);
            redissonLock.lock();
            {//业务逻辑：
                // 从redis中获取商品库存
                int stock = Integer.parseInt(Objects.requireNonNull(redisTemplate.opsForValue().get(KEY_STOCK)));
                AtomicInteger atomicInteger = new AtomicInteger(stock);
                if (atomicInteger.get() > 0) {
                    // 库存-1
                    int remainingStock = atomicInteger.decrementAndGet();
                    // 更新库存
                    redisTemplate.opsForValue().set(KEY_STOCK, String.valueOf(remainingStock));
                    log.info("扣减成功，剩余库存：" + remainingStock);
                } else {
                    log.info("扣减失败，库存不足");
                }
            }
        } finally {
            // -----释放锁------
            redissonLock.unlock();
        }
    }
}
